package net.wicp.tams.common.micro;

import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;

import com.alibaba.druid.pool.DruidDataSource;

import lombok.extern.slf4j.Slf4j;
import net.wicp.tams.common.connector.executor.IBusiManager;
import net.wicp.tams.common.connector.executor.IConfigManager;
import net.wicp.tams.common.connector.executor.busi.KeyConfigManager;
import net.wicp.tams.common.connector.executor.busi.SpringBusiManager;
import net.wicp.tams.common.connector.executor.impl.CommonService;
import net.wicp.tams.commons.Conf;

@Configuration
@Slf4j
public class ConfigInit {
	@Configuration
	@Order(Ordered.HIGHEST_PRECEDENCE)
	protected class InitContext implements ApplicationContextAware, EnvironmentAware {
		@Override
		public void setEnvironment(Environment environment) {
			Properties inputpamas = new Properties();
			Properties tpProps = Conf.copyProperties();
			for (Object key : tpProps.keySet()) {
				String keystr = String.valueOf(key);
				if (environment.containsProperty(keystr)) {
					inputpamas.put(keystr, environment.getProperty(keystr));
				}
			}
			log.info("input parmas:{}", inputpamas.toString());
			Conf.overProp(inputpamas);
		}

		@Override
		public void setApplicationContext(ApplicationContext arg0) throws BeansException {
			// ConfigInit.context = arg0;
		}
	}

	@Configuration
	@ConditionalOnClass(CommonService.class)
	@Order(Ordered.LOWEST_PRECEDENCE)
	public class ConnectionConfig {
		@Bean
		@ConditionalOnMissingBean
		protected IConfigManager createIConfigManager() {
			IConfigManager manage = new KeyConfigManager();
			return manage;
		}

		@Bean
		protected CommonService createExecutor(ApplicationContext context, IConfigManager configManager) {
			CommonService executor = new CommonService();
			IBusiManager busi = new SpringBusiManager(context);
			executor.setBusiManager(busi);
			executor.setConfigManager(configManager);
			return executor;
		}
	}

	@Configuration
	@ConditionalOnClass(name = "com.alibaba.druid.pool.DruidDataSource")
	public class DruidDBConfig {

		@Value("${spring.datasource.url}")
		private String dbUrl;

		@Value("${spring.datasource.username}")
		private String username;

		@Value("${spring.datasource.password}")
		private String password;

		@Value("${spring.datasource.driverClassName}")
		private String driverClassName;

		@Value("${spring.datasource.initialSize}")
		private int initialSize;

		@Value("${spring.datasource.minIdle}")
		private int minIdle;

		@Value("${spring.datasource.maxActive}")
		private int maxActive;

		@Value("${spring.datasource.maxWait}")
		private int maxWait;

		@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
		private int timeBetweenEvictionRunsMillis;

		@Value("${spring.datasource.minEvictableIdleTimeMillis}")
		private int minEvictableIdleTimeMillis;

		@Value("${spring.datasource.validationQuery}")
		private String validationQuery;

		@Value("${spring.datasource.testWhileIdle}")
		private boolean testWhileIdle;

		@Value("${spring.datasource.testOnBorrow}")
		private boolean testOnBorrow;

		@Value("${spring.datasource.testOnReturn}")
		private boolean testOnReturn;

		@Value("${spring.datasource.poolPreparedStatements}")
		private boolean poolPreparedStatements;

		@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize:5}")
		private int maxPoolPreparedStatementPerConnectionSize;

		@Value("${spring.datasource.filters:}")
		private String filters;

		@Value("{spring.datasource.connectionProperties:}")
		private String connectionProperties;

		@Bean // 声明其为Bean实例
		@Primary // 在同样的DataSource中，首先使用被标注的DataSource
		@ConditionalOnClass(name = "com.alibaba.druid.pool.DruidDataSource")
		public DataSource dataSource() {
			DruidDataSource datasource = new DruidDataSource();
			datasource.setUrl(this.dbUrl);
			datasource.setUsername(username);
			datasource.setPassword(password);
			datasource.setDriverClassName(driverClassName);

			// configuration
			datasource.setInitialSize(initialSize);
			datasource.setMinIdle(minIdle);
			datasource.setMaxActive(maxActive);
			datasource.setMaxWait(maxWait);
			datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
			datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
			datasource.setValidationQuery(validationQuery);
			datasource.setTestWhileIdle(testWhileIdle);
			datasource.setTestOnBorrow(testOnBorrow);
			datasource.setTestOnReturn(testOnReturn);
			datasource.setPoolPreparedStatements(poolPreparedStatements);
			datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
			try {
				datasource.setFilters(filters);
			} catch (SQLException e) {
				log.error("druid configuration initialization filter", e);
			}
			datasource.setConnectionProperties(connectionProperties);

			return datasource;
		}
	}
}
